using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Reflection;
using NVelocityTemplateEngine.Interfaces;
using NVelocityTemplateEngine;
using R2ML;

namespace EventAbstractionAPI.CodeGenerator
{
    public class ActionsBuilder
    {
        
        internal string GenerateCode()
        {
            GetActionCodeFromR2ML();

            string assemblyName = Assembly.GetExecutingAssembly().GetName().Name;
            string theNamespace = "EventAbstractionAPI.CodeGenerator";

            INVelocityEngine embeddedEngine = NVelocityEngineFactory.CreateNVelocityAssemblyEngine(assemblyName, theNamespace, true);


            IDictionary context = new Hashtable();

            context.Add("namespace", "WindowsApplication");
            context.Add("Actions", _actionList);
            context.Add("ActionCode", _actionCodeList);
            context.Add("query",_query);
            context.Add("calltype",_calltype);
            context.Add("call",_call);
            context.Add("args",_args);

            String s = embeddedEngine.Process(context, "Resources.Actions.vm");

            return s;
        }

        private void GetActionCodeFromR2ML()
        {
            //args
            String[] parameters = new String[1];

            if (R2ML.RuleFactory.Instance.Initialized())
            {
                //rules are loaded; get the action code.
                foreach (ReactionRule rr in RuleFactory.Instance.ruleBase.ruleSet.reactionRuleList)
                {
                    try
                    {
                        _actionList.Add(rr.Documentation.SourceCode.MethodInstance.Name);

                        if (rr.producedAction.invokeActionExpression != null)
                        {
                            //actionSet a.k.a. query
                            _query = WrapInQuotes(rr.producedAction.invokeActionExpression.contextArguement[0].name);

                            //action call
                            _calltype = "ApplicationObjectModel.CallType.Method";

                            //call
                            _call = WrapInQuotes(rr.producedAction.invokeActionExpression.operationID);

                            //parameters
                            parameters = new String[rr.producedAction.invokeActionExpression.arguements.Length];
                            for (int i = 0; i < rr.producedAction.invokeActionExpression.arguements.Length; i++)
			                {
                                parameters[i] = rr.producedAction.invokeActionExpression.arguements[i].lexicalValue;
			                }

                        }
                        else if (rr.producedAction.assignActionExpression != null)
                        {
                            //actionSet a.k.a. query
                            _query = WrapInQuotes(rr.producedAction.assignActionExpression.contextArguement[0].name);

                            //action call
                            _calltype = "ApplicationObjectModel.CallType.Property";

                            //call
                            _call = WrapInQuotes(rr.producedAction.assignActionExpression.propertyID);

                            //parameters
                            parameters = new String[1];
                            parameters[0] = rr.producedAction.assignActionExpression.arguements[0].lexicalValue;
                        }

                        
                    }
                    catch (Exception)
                    {
                        //there is an issue here if methodinstance/bodyinstance/sourcecode is null (ie not constructed). Completed xml will work. 
                        //TODO: make it optional properly with out try catch.
                    }

                    
                }

                //convert parmeters[] into a single comma separated string and assign to _args

                _args = "";

                for (int i = 0; i < parameters.Length; i++)
			    {
                    //make sure not to put a comma on the last item
                    if (i+1 == parameters.Length)
	                {
                        _args += parameters[i];
                		break;
	                }

            		_args += parameters[i] + ",";
	            }

            }
            else
            {
                throw new Exception("load the r2ml rule list first");
            }
        }

        private string WrapInQuotes(string message)
        {
            return "\"" + message + "\"";
        }

        #region MemberVariables

        ArrayList _actionList = new ArrayList();
        ArrayList _actionCodeList = new ArrayList();
        String _query, _calltype, _call, _args;

        #endregion
    }
}
